/**
 * 
 */
package org.wattdepot.cli.command;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * Computes the carbon content of the source. Given the total carbon generated
 * for the hour starting at the specified timestamp, assuming a constant rate of
 * emission and the total carbon generated for the hour starting at the specified
 * timestamp, assuming a constant rate of emission, the carbon content is
 * (total carbon generated / total energy generated). 
 * 
 * @author George Lee
 *
 */
public class CarbonContentCommand extends WattDepotCliCommand {

  /**
   * 
   * Creates a new instance of the CarbonContentCommand handler.
   * 
   * @param client The instance of WattDepotClient that will handle or commands.
   */
  public CarbonContentCommand(WattDepotClient client) {
    super(client);
  }

  /**
   * Finds the carbon content for a source at a specified time using the provided
   * sampling interval.
   * 
   * @see org.wattdepot.cli.command.WattDepotCliCommand#doCommand(String)
   * 
   * @param command The command from the command line to process.
   * @return The carbon content in lbs/MWh or an error message if one occurs.
   */
  @Override
  public String doCommand(String command) {
    StringTokenizer tokenizer = new StringTokenizer(command);
    List<String> tokens = new ArrayList<String>();
    while (tokenizer.hasMoreTokens()) {
      tokens.add(tokenizer.nextToken());
    }
    
    if (tokens.size() != 5) {
      return this.reportError(PARAMETER_COUNT_ERROR);
    }
    
    if (!tokens.get(0).equals("carboncontent")) {
      return WattDepotCliCommand.reportUnknownCommand(command);
    }
    
    if (!tokens.get(3).equals("sampling-interval")) {
      return this.reportError(PARAMETER_ERROR + tokens.get(3) + ".");
    }
    
    String source = tokens.get(1);
    XMLGregorianCalendar timestamp;
    try {
      timestamp = Tstamp.makeTimestamp(tokens.get(2));
    }
    catch (Exception e) {
      return this.reportError(TSTAMP_ERROR + tokens.get(2) + ".");
    }
    
    int interval;
    try {
      interval = Integer.parseInt(tokens.get(4));
      if (interval <= 0) {
        return this.reportError(RANGE_ERROR);
      }
    }
    catch (NumberFormatException e) {
      return this.reportError(INTERVAL_ERROR + tokens.get(4) + ".");
    }
    
    return this.getCarbonContent(source, timestamp, interval);
  }

  /**
   * Retrieves the carboncontent for a given source at a specified time.
   * 
   * @param source The source to get the information from.
   * @param timestamp The time to get the carboncontent at.
   * @param interval The sampling interval to use to process the carbon content.
   * @return The carbon content expressed in lbs / MWh or an error message.
   */
  private String getCarbonContent(String source, XMLGregorianCalendar timestamp,
      int interval) {
    XMLGregorianCalendar endTime = Tstamp.incrementHours(timestamp, 1);
    try {
      String format = "%.1f %s";
      double carbon = client.getCarbonEmitted(source, timestamp, endTime, interval);
      double energy = client.getEnergyGenerated(source, timestamp, endTime, interval);
      //Convert energy to megawatts.
      energy /= 1000000;
      
      double content = carbon / energy;
      return String.format(format, content, "lbs CO2/MWh");
    }
    catch (NotAuthorizedException e) {
      return this.reportError(CONNECTION_ERROR);
    }
    catch (ResourceNotFoundException e) {
      return this.reportError(SOURCE_ERROR + source + ".");
    }
    catch (BadXmlException e) {
      return this.reportError(BAD_XML_ERROR);
    }
    catch (MiscClientException e) {
      return this.reportError(CONNECTION_ERROR);
    }
  }

  /** 
   * Returns the help string for the CarbonContentCommand.
   * @see org.wattdepot.cli.command.WattDepotCliCommand#getHelp()
   * 
   * @return Information on how to invoke the carbon content command.
   */
  @Override
  public String getHelp() {
    return "carboncontent {source} {timestamp} sampling-interval {interval}\n"
    + "  Computes the carbon content of the source.\n";
  }

}
